# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from datetime import datetime,timedelta

from osapps.common.request import Command,Message
from osapps.friendforsale.model import *

from osapps.friendforsale.tools import *

catalog = {"fix0":"simplefix","fix1":"simplefix","fix2":"simplefix","fix3":"simplefix",
           "reward0":"simplereward","reward1":"simplereward","reward2":"simplereward","reward3":"simplereward",
           "fawn0":"simplefawn","fawn1":"simplefawn","fawn2":"simplefawn","fawn3":"simplefawn",}

class MessageId:
  BUY = "buy"
  RELEASE = "releaseslave"
  BUY_FROM_YOU = "buyfromyou"
  RANSOM = "ransom"
  INIT_PLAYER = "initplayer"

  # error message
  CANT_BUY_MASTER = "cantbuymaster"
  ALREADY_HAVE_SLAVE = "alreadyhaveslave"
  NOT_ENOUGH_MONEY = "notenoughmoney"
  SLAVE_AT_WORK = "slaveatwork"
  NOT_YOUR_SLAVE = "notyourslave"
  DONT_HAVE_MASTER = "donthavemaster"
  ALREADY_HAVE_PLAYER = "alreadyhaveplayer"
  PLAYER_NOT_FOUND = "playernotfound"
  PARAM_ERROR = "paramerror"
  
class getpersonCommand(Command):
  def execute(self):
    playerId = self.request.get("id")
    if not playerId:
      playerId = self.context["vid"]
      
    player = Persist.loadPlayer(self.context["ctn"],playerId)
    
    if not player:
      self.output(Message(MessageId.PLAYER_NOT_FOUND,None))
      return self.END
      
    self.hasError(False)
    
    slaves = Persist.loadSlave(player)
    activities = Persist.loadActivity(player)
    data = {player.userId:player,"slaves":slaves,"activities":activities}

    self.output(data)
    return self.NEXT

class initCommand(Command):
  def execute(self):
    name = self.request.get("name")
    photoUrl = self.request.get("photo")
    player = Player(container=self.context["ctn"],name=name,photoUrl=photoUrl,userId=self.context["vid"])
    player.cash = self.config["init_cash"]
    player.price = self.config["init_price"]
    player.capital = player.cash
    
    Persist.save(player)
    
    self.hasError(False)
    self.output({player.userId:player})
    
    return self.NEXT
        
class buyCommand(Command):
  def execute(self):
    slaveId = self.request.get("slaveid")
    nickname = self.request.get("nickname")
    
    if not slaveId:
      self.output(Message(MessageId.PARAM_ERROR),None)
      return self.NEXT
    
    if nickname:
      nickname = nickname[:20]
    
    viewer = Persist.loadPlayer(self.context["ctn"],self.context["vid"])
    slave = Persist.loadPlayer(self.context["ctn"],slaveId)
    
    if not slave:
      self.output(Message(MessageId.PARAM_ERROR,None))
      return self.END
      
    if Tools.isSlave(viewer,slave):
      self.output(Message(MessageId.ALREADY_HAVE_SLAVE,None))
      return self.END
      
    if Tools.isSlave(slave,viewer):
      self.output(Message(MessageId.CANT_BUY_MASTER,None))
      return self.END
      
    slaveprice = slave.price
    cash = viewer.cash
    if cash < slaveprice:
      self.output(Message(MessageId.NOT_ENOUGH_MONEY,None))
      return self.END
      
    params = {}
    
    #TODO: validate fix time
    lastAI = Persist.getLastActivity(None,slave,ActivityType.FIX)
    now = datetime.now()
    if lastAI:
      if now < lastAI.until:
        self.output(Message(MessageId.SLAVE_AT_WORK,{"activity":lastAI.command,"until":lastAI.until}))
        return self.END
    
    self.hasError(False)
    
    cash = cash - slaveprice
    viewer.cash = cash
    viewer.slavenum = viewer.slavenum + 1
    
    if slave.masterid:
      (origin,oldmasterP,slaveP,tax,newprice) = Profit.count(slaveprice,True)
      orgnMaster = Persist.loadPlayer(self.context["ctn"],slave.masterid)
      orgnMaster.cash = orgnMaster.cash + slaveprice + oldmasterP
      orgnMaster.capital = orgnMaster.capital + oldmasterP
      orgnMaster.slavenum = orgnMaster.slavenum - 1
      params["oldmaster"] = orgnMaster
      
      act = Activity()
      act.container = viewer.container
      act.command = MessageId.BUY_FROM_YOU
      act.setActor(slave)
      act.setTarget(orgnMaster)
      act.setType(ActivityType.BUY)
      
      act.arg1 = str(slaveprice)
      act.arg2 = str(oldmasterP)
      
      Persist.save(orgnMaster)
      Persist.save(act)
      
    else:
      (origin,oldmasterP,slaveP,tax,newprice) = Profit.count(slaveprice,False)
      
    slave.price = newprice
    slave.cash = slave.cash + slaveP
    slave.capital = slave.capital + slaveP
    slave.setMaster(viewer)
    slave.nickname = nickname
    
    params["profit"] = slaveP
    params["viewer"] = viewer
    params["slave"] = slave
    
    ai = Activity()
    ai.container = viewer.container
    ai.setActor(viewer)
    ai.setTarget(slave)
    ai.command = MessageId.BUY
    ai.type = ActivityType.BUY
    ai.arg1 = str(slaveprice)
    
    Persist.save(ai)
    Persist.save(slave)
    Persist.save(viewer)
    
    self.output(Message(MessageId.BUY,params))
    
    return self.NEXT
    
class friendlistCommand(Command):
  def execute(self):
    friends = self.request.get("friends")
    if not friends:
      self.output(Message(MessageId.PLAYER_NOT_FOUND,None))
      return self.END
      
    viewer = Persist.loadPlayer(self.context["ctn"],self.context["vid"])
    
    if not viewer:
      self.output(Message(MessageId.PLAYER_NOT_FOUND,None))
      return self.END
      
    self.hasError(False)
    players = Persist.loadFriends(viewer.container,friends.split(','))
    
    params = {}
    for f in players:
      params[f.userId] = f
      
    self.output(params)
    
    return self.NEXT
    
class cmdlistCommand(Command):
  def execute(self):
    type = self.request.get("type")
    if not type:
      type = "fix"
      
    clist = self.config[type]
    self.hasError(False)
    self.output(clist)
    return self.NEXT
    
class ransomCommand(Command):
  def execute(self):
    viewer = Persist.loadPlayer(self.context["ctn"],self.context["vid"])
    if not viewer:
      self.output(Message(MessageId.PARAM_ERROR,None))
      return self.END
      
    if not viewer.masterid:
      self.output(Message(MessageId.DONT_HAVE_MASTER,None))
      return self.END
      
    master = Persist.loadPlayer(self.context["ctn"],viewer.masterid)
    if not master:
      self.output(Message(MessageId.PARAM_ERROR,None))
      return self.END
      
    if viewer.cash < viewer.price:
      self.output(Message(MessageId.NOT_ENOUGH_MONEY,None))
      return self.END
      
    self.hasError(False)
    
    viewer.cash = viewer.cash - viewer.price
    viewer.capital = viewer.capital - viewer.price
    viewer.free()
    
    master.cash = master.cash + viewer.price
    master.capital = master.capital + viewer.price
    master.slavenum = master.slavenum + 1
    
    activity = Activity()
    activity.setActor(viewer)
    activity.setTarget(master)
    activity.container = viewer.container
    activity.command = MessageId.RANSOM
    activity.type = ActivityType.BUY
    
    Persist.save(viewer)
    Persist.save(master)
    Persist.save(activity)
    
    self.output(Message(MessageId.RANSOM,{"viewer":viewer,"master":master}))
    return self.NEXT
    
class dostuffCommand(Command):
  def pre(self,context):
    if Command.pre(self,context) == self.NEXT:
      if self.loadPlayer() == self.END:
        self.output(Message(MessageId.PARAM_ERROR,None))
        return self.END
      
      return self.NEXT
    else:
      return self.END
      
  def loadPlayer(self):
      targetId = self.request.get("targetid")
      
      if not targetId:
        return self.END
        
      self.viewer = Persist.loadPlayer(self.context["ctn"],self.context["vid"])
      self.target = Persist.loadPlayer(self.context["ctn"],targetId)
      
      if (not self.viewer) or (not self.target):
        return self.END
        
      return self.NEXT
      
  def newActivity(self,type):
      activity = Activity()
      activity.container = self.viewer.container
      activity.setActor(self.viewer)
      activity.setTarget(self.target)
      activity.type = type
      activity.command = self.getMessageId()
      
      return activity
      
  def getMessageId(self):
      return self.request.get("cmd")
      
class simplefixCommand(dostuffCommand):
  def execute(self):
    if not Tools.isSlave(self.viewer,self.target):
      self.output(Message(MessageId.NOT_YOUR_SLAVE,None))
      return self.END
      
    lastAI = Persist.getLastActivity(self.viewer,self.target,ActivityType.FIX)
    now = datetime.now()
    if(lastAI):
      if(now < lastAI.until):
        self.output(Message(MessageId.SLAVE_AT_WORK,{"activity":lastAI.command,"until":lastAI.until}))
        return self.END
    
    activity = self.newActivity(ActivityType.FIX)
    activity.until = Tools.lock(now,int(self.config["fix_interval"]))
    
    Persist.save(self.viewer)
    Persist.save(self.target)
    Persist.save(activity)
    
    self.hasError(False)
    self.output(Message(self.getMessageId(),{"viewer":self.viewer,"target":self.target}))
    return self.NEXT
  
class simplerewardCommand(dostuffCommand):
  def execute(self):
    if not Tools.isSlave(self.viewer,self.target):
      self.output(Message(MessageId.NOT_YOUR_SLAVE,None))
      return self.END
      
    lastAI = Persist.getLastActivity(self.viewer,self.target,ActivityType.REWARD)
    now = datetime.now()
    if(lastAI and now < lastAI.until):
      self.output(Message(MessageId.SLAVE_AT_WORK,{"activity":lastAI.command,"until":lastAI.until} ))
      return self.END

    activity = self.newActivity(ActivityType.REWARD)
    activity.until = Tools.lock(now,int(self.config["reward_interval"]))

    Persist.save(self.viewer)
    Persist.save(self.target)
    Persist.save(activity)

    self.hasError(False)
    self.output(Message(self.getMessageId(),{"viewer":self.viewer,"target":self.target}))
    return self.NEXT

class simplefawnCommand(dostuffCommand):    
  def execute(self):
    if not Tools.isSlave(self.target,self.viewer):
      self.output(Message(MessageId.NOT_YOUR_SLAVE,None))
      return self.END
      
    lastAI = Persist.getLastActivity(self.viewer,self.target,ActivityType.FAWN)
    now = datetime.now()
    if(lastAI and now < lastAI.until):
      self.output(Message(MessageId.SLAVE_AT_WORK,{"activity":lastAI.command,"until":lastAI.until} ))
      return self.END

    activity = self.newActivity(ActivityType.FAWN)
    activity.until = Tools.lock(now,int(self.config["fawn_interval"]))

    Persist.save(self.viewer)
    Persist.save(self.target)
    Persist.save(activity)

    self.hasError(False)
    self.output(Message(self.getMessageId(),{"viewer":self.viewer,"target":self.target}))
    return self.NEXT
    
class releaseCommand(dostuffCommand):
  def execute(self):
    if not Tools.isSlave(self.viewer,self.target):
      self.output(Message(MessageId.NOT_YOUR_SLAVE,None))
      return self.END
      
    self.hasError(False)
    self.target.free()
    self.viewer.capital = self.viewer.capital - self.target.price
    self.viewer.slavenum = self.viewer.slavenum - 1
    
    activity = self.newActivity(ActivityType.BUY)
    activity.command = MessageId.RELEASE
    
    Persist.save(self.target)
    Persist.save(self.viewer)
    Persist.save(activity)
    
    self.output(Message(MessageId.RELEASE,None))
    return self.NEXT